package com.xsq.wifi.utils;

import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * 编写人：李振德
 * 创建时间：2025/5/27
 */
public class NetworkHelper {
    private static final String TAG = "NetworkHelper";
    private static final int TIMEOUT_MS = 5000;
    private static final int DEVICE_PORT = 3333;
    private static final byte PROTOCOL_VERSION = 0x01;
    private static final short PCP_STA_OK = 0x0001;

    /**
     * 基础通信方法
     * @param deviceIp 设备IP
     * @param cmd 命令字
     * @param payload 请求数据体
     * @param isLittleEndian 是否小端序
     * @return 响应数据
     */
    public static Response sendRequest(String deviceIp, byte cmd, byte[] payload, boolean isLittleEndian) throws IOException {
        Socket socket = null;
        try {
            // 1. 建立连接
            socket = new Socket();
            socket.connect(new InetSocketAddress(deviceIp, DEVICE_PORT), TIMEOUT_MS);
            socket.setSoTimeout(TIMEOUT_MS);

            // 2. 构建请求
            ByteBuffer requestBuffer = ByteBuffer.allocate(8 + (payload != null ? payload.length : 0));
            requestBuffer.order(isLittleEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
            requestBuffer.put(PROTOCOL_VERSION);
            requestBuffer.put(cmd);
            requestBuffer.putShort((short) 0x0000); // 默认value
            requestBuffer.putInt(payload != null ? payload.length : 0);
            if (payload != null) {
                requestBuffer.put(payload);
            }

            // 3. 发送请求
            OutputStream out = socket.getOutputStream();
            out.write(requestBuffer.array());
            out.flush();

            // 4. 接收响应头
            byte[] header = readExactly(socket.getInputStream(), 8);

            // 5. 解析响应头
            ByteOrder responseOrder = detectByteOrder(header);
            ByteBuffer headerBuffer = ByteBuffer.wrap(header).order(responseOrder);

            byte version = headerBuffer.get();
            byte responseCmd = headerBuffer.get();
            short status = headerBuffer.getShort();
            int dataLength = headerBuffer.getInt();

            // 6. 验证协议
            if (version != PROTOCOL_VERSION || responseCmd != cmd) {
                throw new IOException("Protocol mismatch");
            }
            if (status != PCP_STA_OK) {
                throw new IOException("Device error: 0x" + Integer.toHexString(status & 0xFFFF));
            }

            // 7. 读取数据
            byte[] data = dataLength > 0 ? readExactly(socket.getInputStream(), dataLength) : new byte[0];

            return new Response(version, responseCmd, status, data, responseOrder);
        } finally {
            closeSocket(socket);
        }
    }

    public static Response sendRequest1(String deviceIp, byte cmd, byte[] payload, boolean isLittleEndian) throws IOException {
        Socket socket = null;
        try {
            // 1. 建立连接
            socket = new Socket();
            socket.connect(new InetSocketAddress(deviceIp, DEVICE_PORT), TIMEOUT_MS);
            socket.setSoTimeout(TIMEOUT_MS);

            // 2. 构建请求
            ByteBuffer requestBuffer = ByteBuffer.allocate(8 + (payload != null ? payload.length : 0));
            requestBuffer.order(isLittleEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
            requestBuffer.put(PROTOCOL_VERSION);
            requestBuffer.put(cmd);
            short controlValue = (cmd == ProtocolConstants.CMD_PLAYERPAUSE) ?
                    (payload != null && payload.length > 0 && payload[0] == 0x01) ?
                            (short) 0x0001 : (short) 0x0000 :
                    (short) 0x0000;
            requestBuffer.putShort(controlValue);
            requestBuffer.putInt(payload != null ? payload.length : 0);
            if (payload != null) {
                requestBuffer.put(payload);
            }

            // 3. 发送请求
            OutputStream out = socket.getOutputStream();
            out.write(requestBuffer.array());
            out.flush();

            // 4. 接收响应头
            byte[] header = readExactly(socket.getInputStream(), 8);

            // 5. 解析响应头
            ByteOrder responseOrder = detectByteOrder(header);
            ByteBuffer headerBuffer = ByteBuffer.wrap(header).order(responseOrder);

            byte version = headerBuffer.get();
            byte responseCmd = headerBuffer.get();
            short status = headerBuffer.getShort();
            int dataLength = headerBuffer.getInt();

            // 6. 验证协议
            if (version != PROTOCOL_VERSION || responseCmd != cmd) {
                throw new IOException("Protocol mismatch");
            }
            if (status != PCP_STA_OK) {
                throw new IOException("Device error: 0x" + Integer.toHexString(status & 0xFFFF));
            }

            // 7. 读取数据
            byte[] data = dataLength > 0 ? readExactly(socket.getInputStream(), dataLength) : new byte[0];

            return new Response(version, responseCmd, status, data, responseOrder);
        } finally {
            closeSocket(socket);
        }
    }

    private static byte[] readExactly(InputStream in, int length) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        byte[] chunk = new byte[1024];
        int remaining = length;

        while (remaining > 0) {
            int read = in.read(chunk, 0, Math.min(chunk.length, remaining));
            if (read == -1) throw new IOException("Unexpected end of stream");
            buffer.write(chunk, 0, read);
            remaining -= read;
        }
        return buffer.toByteArray();
    }

    private static ByteOrder detectByteOrder(byte[] header) {
        ByteBuffer buffer = ByteBuffer.wrap(header).order(ByteOrder.BIG_ENDIAN);
        short statusBigEndian = buffer.getShort(2);
        return statusBigEndian == 0x0100 ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN;
    }

    static void closeSocket(Socket socket) {
        if (socket != null) {
            try {
                socket.setSoLinger(true, 0);
                try { socket.shutdownInput(); } catch (IOException ignored) {}
                try { socket.shutdownOutput(); } catch (IOException ignored) {}
                socket.close();
            } catch (IOException e) {
                Log.w(TAG, "Error closing socket", e);
            }
        }
    }

    public static class Response {
        public final byte version;
        public final byte command;
        public final short status;
        public final byte[] data;
        public final ByteOrder byteOrder;

        public Response(byte version, byte command, short status, byte[] data, ByteOrder byteOrder) {
            this.version = version;
            this.command = command;
            this.status = status;
            this.data = data;
            this.byteOrder = byteOrder;
        }
    }
}
